package com.quxue.im.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.quxue.im.common.enums.SmsTypeEnum;
import com.quxue.im.exception.LogicException;
import com.quxue.im.req.user.*;
import com.quxue.im.service.IChatMsgService;
import com.quxue.im.util.SmsUtils;
import com.quxue.im.vo.AjaxResult;
import com.quxue.im.entity.ChatUser;
import com.quxue.im.mapper.ChatUserMapper;
import com.quxue.im.service.IChatUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.quxue.im.vo.user.UserInfoVo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Objects;

import static com.quxue.im.common.Const.DEFAULT_PORTRAIT;
import static com.quxue.im.common.enums.SmsTypeEnum.LOGIN;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author jinken
 * @since 2023-11-10
 */
@Service
public class ChatUserServiceImpl extends ServiceImpl<ChatUserMapper, ChatUser> implements IChatUserService {

    @Resource
    private SmsUtils smsUtils;


    @Resource
    private IChatMsgService chatMsgService;

    @Override
    public AjaxResult login(LoginReq loginReq) {

        ChatUser chatUser = this.selectByPhone(loginReq.getPhone());
        //账号密码正确，登录成功
        if (chatUser != null) {

            /**
             * 比较密码：用户输入密码+salt 和 数据库密码比对
             */
            String password = loginReq.getPassword();
            String salt = chatUser.getSalt();
            //密码加密
            String saltPasword = SaSecureUtil.md5BySalt(password, salt);
            System.out.println("saltPasword = " + saltPasword);
            if (chatUser.getPassword().equals(saltPasword)) {

                //如果已经有一个客户端登录了，就踢下线
                if(StpUtil.isLogin(chatUser.getUserId())){
                    System.out.println("踢下线其他登录地方---");
                    StpUtil.kickout(chatUser.getUserId());
                }

                //使用sa-token的登录
                StpUtil.login(chatUser.getUserId());
                //获取token响应给前端
                String tokenValue = StpUtil.getTokenInfo().getTokenValue();
                return AjaxResult.success(tokenValue);
            }
        }

        return AjaxResult.error("手机或者密码错误");
    }

    @Override
    public AjaxResult loginByCode(LoginByCodeReq loginReq) {

        ChatUser chatUser = this.selectByPhone(loginReq.getPhone());
        //账号密码正确，登录成功
        if (chatUser != null) {
            //校验验证码
            smsUtils.verifySms(loginReq.getPhone(), loginReq.getCode(),LOGIN.getType());
            //登录认证
            StpUtil.login(chatUser.getUserId());

            //获取token响应给前端
            String tokenValue = StpUtil.getTokenInfo().getTokenValue();
            return AjaxResult.success(tokenValue);
        }
        return AjaxResult.error("手机或者密码错误");
    }

    @Override
    public ChatUser selectByPhone(String phone) {
        QueryWrapper<ChatUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone", phone);
        return this.getOne(queryWrapper);
    }

    @Override
    public AjaxResult getInfo() {
        if(StpUtil.isLogin()){
            SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
            Object loginId = tokenInfo.getLoginId();
            if(Objects.nonNull(loginId)){
                ChatUser chatUser = this.getById(Long.valueOf(loginId.toString()));
                UserInfoVo userInfoVo = new UserInfoVo();
                BeanUtil.copyProperties(chatUser,userInfoVo);
                return AjaxResult.success(userInfoVo);
            }
        }
        return AjaxResult.error("登录超时,请重新登录");
    }

    @Override
    public AjaxResult register(RegisterReq registerReq) {

        //1.检查验证码是否错误
        smsUtils.verifySms(registerReq.getPhone(),registerReq.getCode(), SmsTypeEnum.REGISTER.getType());
        //2.检查数据库是否存在
        ChatUser existsUser = this.selectByPhone(registerReq.getPhone());
        if(Objects.nonNull(existsUser)){
            throw new LogicException("手机号已经存在，请换一个手机号");
        }
        //3.封装数据并存储数据库

        //生成盐用于密码加密
        String salt = RandomUtil.randomString(4);
        //密码加密 ： MD5加密（密码+salt）
        String password = SaSecureUtil.md5BySalt(registerReq.getPassword(), salt);



        ChatUser user = new ChatUser();
        user.setUserId(IdUtil.getSnowflakeNextId());
        user.setChatNo(RandomUtil.randomString(10));
        user.setPhone(registerReq.getPhone());
        user.setSalt(salt);
        user.setPassword(password);
        user.setCreateTime(LocalDateTime.now());
        user.setNickName(registerReq.getNickName());
        //设置默认头像
        user.setPortrait(DEFAULT_PORTRAIT);

        //保存数据
        this.save(user);

        return AjaxResult.success();
    }

    @Override
    public AjaxResult forget(ForgetReq forgetReq) {
        //1，校验验证码是否正确
        smsUtils.verifySms(forgetReq.getPhone(), forgetReq.getCode(),SmsTypeEnum.FORGET.getType());

        //生成盐用于密码加密
        String salt = RandomUtil.randomString(4);
        //密码加密 ： MD5加密（密码+salt）
        String password = SaSecureUtil.md5BySalt(forgetReq.getPassword(), salt);



        ChatUser chatUser = new ChatUser();
        chatUser.setPassword(password);
        chatUser.setSalt(salt);

        //2，根据手机号修改密码
        UpdateWrapper<ChatUser> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("phone",forgetReq.getPhone());

        this.update(chatUser,updateWrapper);

        return AjaxResult.success();
    }

    @Override
    public AjaxResult updatePassword(PassReq passReq) {

        /**
         * 修改步骤
         * 1，比对原密码
         * 2，修改密码
         */
        ChatUser chatUser = this.getById(StpUtil.getLoginIdAsLong());

        //请求密码+salt(盐)和原密码比对
        String password = SaSecureUtil.md5BySalt(passReq.getPassword(), chatUser.getSalt());
        if(!chatUser.getPassword().equals(password)){
            LogicException.logicException("原密码错误，请重新输入原密码！");
        }
        //生成新的盐
        String salt = RandomUtil.randomString(4);
        //新密码+salt加密
        String newPassword = SaSecureUtil.md5BySalt(passReq.getPwd(),salt);
        //设置用户的新salt和新的密码
        chatUser.setSalt(salt);
        chatUser.setPassword(newPassword);

        //修改用户数据
        this.updateById(chatUser);

        return AjaxResult.success();
    }

    @Override
    public void refresh() {
        //获取登录用户
        long userId = StpUtil.getLoginIdAsLong();

        // 拉取离线消息
        chatMsgService.pullMsg(userId);
    }
}
